﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading;
using SudokuGame.Logic;
using SudokuGame.Interface;


namespace SudokuGame.Logic
{
    class SudokuController
    {
        private Graphics buffer, enbuffer;
        private Sudoku sudoku, enemysudoku;
        private Point current;
        private Thread repainter, enemyrepainter;
        public bool solved = false;
        private BufferedGraphics g, gmini;
        //размеры клетки и отступы.
        private const int myCellSize = 25, myTopMarg = 15, myLeftMarg = 20;
        private const int enCellSize = 15, enTopMarg = 5, enLeftMarg = 5;
        private const int myFontSize = 13, enFontSize = 8;
        private static Brush  myBr = Brushes.DarkGreen, enBr = Brushes.DeepPink, currBr = Brushes.Gold;
        private Pen mySoft = new Pen(myBr, 2);
        private Pen myHard = new Pen(myBr, 4);
        private Font mySoftF = new Font(FontFamily.GenericSansSerif, myFontSize, FontStyle.Regular);
        private Font myHardF = new Font(FontFamily.GenericSansSerif, myFontSize, FontStyle.Bold);

        private Pen enSoft = new Pen(enBr, 1);
        private Pen enHard = new Pen(enBr, 2);
        private Font enSoftF = new Font(FontFamily.GenericMonospace, enFontSize, FontStyle.Regular);
        private Font enHardF = new Font(FontFamily.GenericMonospace, enFontSize, FontStyle.Bold);
        private StringFormat sf = new StringFormat();
            

        private String _sud = "1xx2985x698x365x41x534x782xx21xx34x5x39x5x21x5x61xx39xx157x968x29x836x543x8541xx2";
        private String _sud2 = "1xx2985x698x365x41x534x782xx21xx34x5x39x5x21x5x61xx39xx157x968x29x836x543x8541xx2";
        public SudokuController(String adress, ref BufferedGraphics g, ref BufferedGraphics gmini)
        {
            this.g     = g;
            this.gmini = gmini;

            
            sf.Alignment = StringAlignment.Center;

            this.sudoku = new Sudoku(_sud);
            this.enemysudoku = new Sudoku(_sud2);

            buffer   = g.Graphics;
            enbuffer = gmini.Graphics;
            current = new Point(0, 0);
            initCurrent();
            //this.enemysudoku = getUpdate().sudoku;
            //часто запрашиваем апдейты - из них выковыриваем три аттрибута - 
            // булево - есть ли перемешивание, булево - отреагировали ли на предыдущее перемещение
            // и строковое - текущее судоку противника.
            
            repainter = new Thread(
                delegate(){
                    repaint(this.g, true);
                }
            );
            
            enemyrepainter = new Thread(
                delegate() { 
                    repaint(this.gmini, false); 
                }
            );
            repainter.IsBackground = true;
            repainter.Start();
            enemyrepainter.IsBackground = true;
            enemyrepainter.Start();
            
        }

        private void initCurrent()
        {
            for (int i = 0; i < 81; i++)
            {
                if (sudoku.initial[i % 9, i / 9] == -1)
                {
                    current.X = i % 9;
                    current.Y = i / 9;
                    return;
                }
            }
          
        }


        public void repaint(BufferedGraphics gr, bool isMy)
        {
            while (true){
                if (isMy)  paint(isMy, buffer);
                else paint(isMy, enbuffer);
                gr.Render();
                Thread.Sleep(0);
            }
        }


        public void Shuffle()
        {
            Random rand = new Random();
            int x = rand.Next(6718464);
            sudoku.shiftBigLine(x/279936 % 6);
            sudoku.shiftBigColumn(x/46556 %6);
            sudoku.shiftLine(0,x % 6);
            sudoku.shiftLine(1, x/6 % 6);
            sudoku.shiftLine(2, x/36 % 6);
            sudoku.shiftCol(0, x / 216 % 6);
            sudoku.shiftCol(1, x / 1296 % 6);
            sudoku.shiftCol(2, x / 7776 % 6);
            sudoku.mirror(x/1679616 % 4); 
        }


        
        //@param x,y - coordinates of point.
        //@summary - method sets current piece to one, that contains point of mouseclick.
        public void changeCurrent(int x, int y)
        {
            if (x < myLeftMarg || y < myTopMarg) return;
            x = (x - myLeftMarg) / myCellSize;
            y = (y - myTopMarg) / myCellSize;
            if (x >= 0 && y >=0 &&
                x <  9 && y <  9   )
            {
                //ToDo
                if (sudoku.initial[x,y] == -1)
                {
                    current.X = x;
                    current.Y = y;
                }
            }
            
            
        }

        public void changeCurrent(Form1.Direction dir)
        {
            int newx = current.X, newy = current.Y;
            switch (dir){

                case Form1.Direction.Up:
                    {
                        /*
                        for (int i = 1; i < 9; i++)
                        {
                            if (sudoku.initial[current.X, (current.Y - i+9) % 9] == -1)
                            {
                                newy = (current.Y - i + 9) % 9;
                                break;
                            }
                        }
                        */
                        newy = (current.Y + 8) % 9;
                        break;

                    }

                case Form1.Direction.Down:
                    {
                        /*for (int i = 1; i < 9; i++)
                        {
                            if (sudoku.initial[current.X, (current.Y + i) % 9] == -1)
                            {
                                newy = (current.Y + i) % 9;
                                break;
                            }
                        }*/
                        newy = (current.Y + 1) % 9;
                        break;
                    }

                case Form1.Direction.Right:
                    {
                        /*for (int i = 1; i < 9; i++)
                        {
                            if (sudoku.initial[(current.X+i)%9, current.Y] == -1)
                            {
                                newx = (current.X + i) % 9;
                                break;
                            }
                        }*/
                        newx = (current.X + 1) % 9;
                        break;
                    }

                case Form1.Direction.Left:
                    {
                        /*for (int i = 1; i < 9; i++)
                        {
                            if (sudoku.initial[(current.X - i+9) % 9, current.Y] == -1)
                            {
                                newx = (current.X - i+9) % 9;
                                break;
                            }
                        }*/
                        newx = (current.X + 8) % 9;
                        break;
                    }
                   

                }
                current.X = newx; current.Y = newy;
        }

        public bool addToSolution(int number)
        {   
            if (number>0 && number <10) sudoku.addToSolution(number, current.X, current.Y);
            return sudoku.solved();
        }

        public bool removeFromSolution()
        {
            return sudoku.removeFromSolution(current.X, current.Y);
        }



        public void paint(bool my, Graphics gr)
        {
            
            gr.Clear(Color.LightGray);
            if (my)
            {
                gr.FillRectangle(currBr, myLeftMarg + current.X * myCellSize, myTopMarg + current.Y * myCellSize, myCellSize, myCellSize);
                
                for (int i = 0; i < 10; i++)
                {

                    if (i % 3 != 0)
                    {
                        gr.DrawLine(mySoft, myLeftMarg, myTopMarg + i * myCellSize,
                                    myLeftMarg + 9 * myCellSize, myTopMarg + i * myCellSize);
                        gr.DrawLine(mySoft, myLeftMarg + i * myCellSize, myTopMarg,
                                    myLeftMarg + i * myCellSize, myTopMarg + 9 * myCellSize);
                    }
                    else
                    {
                        gr.DrawLine(myHard, myLeftMarg, myTopMarg + i * myCellSize,
                                    myLeftMarg + 9 * myCellSize, myTopMarg + i * myCellSize);
                        gr.DrawLine(myHard, myLeftMarg + i * myCellSize, myTopMarg,
                                    myLeftMarg + i * myCellSize, myTopMarg + 9 * myCellSize);
                    }

                }


                for (int i = 0; i < 9; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        if (sudoku.initial[i, j] == -1)
                        {
                            if (sudoku.solution[i, j] != -1)
                            {
                                gr.DrawString(Convert.ToString(sudoku.solution[i, j]), mySoftF, myBr,
                                    new Rectangle(myLeftMarg + i * myCellSize+1, myTopMarg + j * myCellSize+3, myCellSize, myCellSize), sf);
                            }

                        }
                        else gr.DrawString(Convert.ToString(sudoku.solution[i, j]), myHardF, myBr,
                                    new Rectangle(myLeftMarg + i * myCellSize+1, myTopMarg + j * myCellSize+3, myCellSize, myCellSize), sf);
                    }
                }
            }



            else
            {


                for (int i = 0; i < 10; i++)
                {
                    if (i % 3 != 0)
                    {
                        gr.DrawLine(enSoft, enLeftMarg, enTopMarg + i * enCellSize,
                                    enLeftMarg + 9 * enCellSize, enTopMarg + i * enCellSize);
                        gr.DrawLine(enSoft, enLeftMarg + i * enCellSize, enTopMarg,
                                    enLeftMarg + i * enCellSize, enTopMarg + 9 * enCellSize);
                    }
                    else
                    {
                        gr.DrawLine(enHard, enLeftMarg, enTopMarg + i * enCellSize,
                                    enLeftMarg + 9 * enCellSize, enTopMarg + i * enCellSize);
                        gr.DrawLine(enHard, enLeftMarg + i * enCellSize, enTopMarg,
                                    enLeftMarg + i * enCellSize, enTopMarg + 9 * enCellSize);
                    }
                }



                for (int i = 0; i < 9; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        if (enemysudoku.initial[i, j] == -1)
                        {
                            if (enemysudoku.solution[i, j] != -1)
                            {
                                gr.DrawString(Convert.ToString(enemysudoku.solution[i, j]), enSoftF, enBr,
                                    new Rectangle(enLeftMarg + i * enCellSize, enTopMarg + j * enCellSize, enCellSize, enCellSize), sf);
                            }

                        }
                        else gr.DrawString(Convert.ToString(enemysudoku.solution[i, j]), enHardF, enBr,
                                    new Rectangle(enLeftMarg + i * enCellSize, enTopMarg + j * enCellSize, enCellSize, enCellSize), sf);
                    }
                }



            }
        }
    }

}
